package com.bolt.report.engine.export.excel;

import com.bolt.common.io.IoUtil;
import com.bolt.common.utils.ImageUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.report.definition.Align;
import com.bolt.report.definition.PaperType;
import com.bolt.report.definition.PrintOrder;
import com.bolt.report.definition.StyleDefinition;
import com.bolt.report.engine.OutputStreamExporterOutput;
import com.bolt.report.engine.export.AbstractExporter;
import com.bolt.report.engine.fill.FillImageElement;
import com.bolt.report.engine.model.ReportPrint;
import com.bolt.report.util.ToolUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFPrintSetup;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;


public abstract class BaseExcelExporter extends AbstractExporter<OutputStreamExporterOutput> {

    protected Sheet sheet;

    protected SXSSFWorkbook workbook;


    protected OutputStream outputStream;

    public BaseExcelExporter() {
        super();
    }

    public BaseExcelExporter(Map<String, Object> parameters) {
        super(parameters);
    }

    protected Sheet createSheet(SXSSFWorkbook wb, ReportPrint reportPrint, String name) {
        Sheet sheet = null;
        if (name == null) {
            sheet = wb.createSheet();
        } else {
            sheet = wb.createSheet(name);
        }
        XSSFPrintSetup printSetup = (XSSFPrintSetup) sheet.getPrintSetup();
        PrintOrder printOrder = reportPrint.getPrintOrderValue();
        if (printOrder.equals(PrintOrder.HORIZONTAL)) {
            printSetup.setOrientation(PrintOrientation.LANDSCAPE);
        }
        setPaperType(reportPrint.getPaper().getPaperType(), printSetup);
        int leftMargin = reportPrint.getLeftMargin();
        int rightMargin = reportPrint.getRightMargin();
        int topMargin = reportPrint.getTopMargin();
        int bottomMargin = reportPrint.getBottomMargin();
        sheet.setMargin(Sheet.LeftMargin, ToolUtil.pointToinches(leftMargin));
        sheet.setMargin(Sheet.RightMargin, ToolUtil.pointToinches(rightMargin));
        sheet.setMargin(Sheet.TopMargin, ToolUtil.pointToinches(topMargin));
        sheet.setMargin(Sheet.BottomMargin, ToolUtil.pointToinches(bottomMargin));
        return sheet;
    }

    protected boolean setPaperType(PaperType paperType, XSSFPrintSetup printSetup) {
        boolean setup = false;
        switch (paperType) {
            case A0:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A1:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A2:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A3:
                printSetup.setPaperSize(PaperSize.A3_PAPER);
                setup = true;
                break;
            case A4:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                setup = true;
                break;
            case A5:
                printSetup.setPaperSize(PaperSize.A5_PAPER);
                setup = true;
                break;
            case A6:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A7:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A8:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A9:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case A10:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B0:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B1:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B2:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B3:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B4:
                printSetup.setPaperSize(PaperSize.B4_PAPER);
                setup = true;
                break;
            case B5:
                printSetup.setPaperSize(PaperSize.B4_PAPER);
                setup = true;
                break;
            case B6:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B7:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B8:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B9:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case B10:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
            case CUSTOM:
                printSetup.setPaperSize(PaperSize.A4_PAPER);
                break;
        }
        return setup;
    }

    protected int buildImageFormat(String imageType) {
        int type = Workbook.PICTURE_TYPE_PNG;
        if (StrUtil.isBlank(imageType)) {
            return type;
        }
        imageType = imageType.toLowerCase();
        if (imageType.endsWith("jpg") || imageType.endsWith("jpeg")) {
            type = Workbook.PICTURE_TYPE_JPEG;
        }
        return type;
    }

    protected void buildImage(com.bolt.report.engine.model.Cell cell) throws IOException {
        FillImageElement imageElement = (FillImageElement) cell.getElement();
        InputStream inputStream = ImageUtil.base64DataToInputStream(imageElement.getValue());
        int width = imageElement.getWidth();
        int height = imageElement.getHeight();
        int leftMargin = 0, topMargin = 0;


        int wholeWidth = imageElement.getWidth();
        int wholeHeight = imageElement.getHeight();

        StyleDefinition style = cell.getStyle();
        HorizontalAlignment align;
        if (style.getAlign().equals(Align.left)) {
            align = HorizontalAlignment.LEFT;
        } else if (style.getAlign().equals(Align.center)) {
            align = HorizontalAlignment.CENTER;
        } else if (style.getAlign().equals(Align.right)) {
            align = HorizontalAlignment.RIGHT;
        } else {
            align = HorizontalAlignment.LEFT;
        }
        if (align.equals(HorizontalAlignment.CENTER)) {
            leftMargin = (wholeWidth - width) / 2;
        } else if (align.equals(HorizontalAlignment.RIGHT)) {
            leftMargin = wholeWidth - width;
        }
        VerticalAlignment valign;

        if (style.getValign().equals(Align.top)) {
            valign = VerticalAlignment.TOP;
        } else if (style.getValign().equals(Align.middle)) {
            valign = VerticalAlignment.CENTER;
        } else if (style.getValign().equals(Align.bottom)) {
            valign = VerticalAlignment.BOTTOM;
        } else {
            valign = VerticalAlignment.TOP;
        }

        if (valign.equals(VerticalAlignment.CENTER)) {
            topMargin = (wholeHeight - height) / 2;
        } else if (valign.equals(VerticalAlignment.BOTTOM)) {
            topMargin = wholeHeight - height;
        }

        try {
            CreationHelper creationHelper = this.workbook.getCreationHelper();
            Drawing<?> drawing = sheet.createDrawingPatriarch();

            byte[] bytes = IoUtil.readBytes(inputStream);
            int pictureFormat = buildImageFormat(imageElement.getImageType());
            int pictureIndex = this.workbook.addPicture(bytes, pictureFormat);
            XSSFClientAnchor anchor = (XSSFClientAnchor) creationHelper.createClientAnchor();
            anchor.setCol1(cell.getColumnIndex());
            anchor.setCol2(cell.getColumnIndex() + (cell.getColSpan() == 0 ? 1 : cell.getColSpan()));
            anchor.setRow1(cell.getRowIndex());
            anchor.setRow2(cell.getRowIndex() + (cell.getRowSpan() == 0 ? 1 : cell.getRowSpan()));
            anchor.setDx1(leftMargin);
            anchor.setDx2(width);
            anchor.setDy1(topMargin);
            anchor.setDy2(height);

            anchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE);


            drawing.createPicture(anchor, pictureIndex);
        } finally {
            IoUtil.close(inputStream);
        }
    }
}